package com.sonix.oidbluetooth;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;

import com.google.common.collect.ArrayListMultimap;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sonix.app.Api;
import com.sonix.app.App;
import com.sonix.base.BaseActivity;
import com.sonix.base.BindEventBus;
import com.sonix.oidbluetooth.service.BeibiService;
import com.sonix.oidbluetooth.view.PopupColor;
import com.sonix.oidbluetooth.view.PopupListener;
import com.sonix.oidbluetooth.view.PopupMore;
import com.sonix.oidbluetooth.view.PopupOffline;
import com.sonix.oidbluetooth.view.PopupOfflineProgress;
import com.sonix.oidbluetooth.view.PopupReplay;
import com.sonix.ota.OTAActivity;
import com.sonix.surfaceview.DrawView;
import com.sonix.util.ColorUtil;
import com.sonix.util.DataHolder;
import com.sonix.util.DotUtils;
import com.sonix.util.Events;
import com.sonix.util.FileUtils;
import com.sonix.util.LogUtils;
import com.tqltech.tqlpencomm.bean.Dot;
import com.tqltech.tqlpencomm.util.BLEFileUtil;

import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * 主界面
 */
@BindEventBus
public class MainActivity extends BaseActivity implements View.OnClickListener {

    private static final String TAG = MainActivity.class.getSimpleName();

    private static final String LOG_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/TQL/"; //绘制数据保存目录

    private static final int MSG_REPLAY = 0;
    private static final boolean isSaveLog = false;

    private TextView tv_pen_name;
    private TextView tv_pen_status;

    private RelativeLayout mylayout;
    private DrawView mPenView;

    private LinearLayout ll_bottom;

    private LinearLayout itv_width;
    private LinearLayout itv_color;
    private LinearLayout itv_clear;
    private LinearLayout itv_replay;
    private LinearLayout itv_more;

    private PopupWindow popup;

    private boolean hasMeasured = false;
    private double A5_WIDTH;                                    //本子宽
    private double A5_HEIGHT;                                   //本子高
    private int BG_WIDTH;                                       //显示背景图宽
    private int BG_HEIGHT;                                      //显示背景图高
    private int gCurPageID = -1;                                //当前PageID
    private int gCurBookID = -1;                                //当前BookID
    private int gColor = 1;                                     //笔迹颜色
    private int gWidth = 1;                                     //笔迹粗细
    private int gSpeed = 3;                                     //笔迹回放速度
    private int gProgress = 0;                                  //离线数据下载进度

    private boolean startOffline;                               //开始下载离线标记
    private boolean showProgress;                               //显示离线下载进度标记
    private boolean bIsReplay;                                  //回放标记

    private int gReplayTotalNumber = 0;                         //回放数据总量
    private int gReplayCurrentNumber = 0;                       //当前回放数据位置标识

//    private static ArrayListMultimap<Integer, Dots> dot_number = ArrayListMultimap.create();  //Book=100笔迹数据
//    private static ArrayListMultimap<Integer, Dots> dot_number1 = ArrayListMultimap.create(); //Book=0笔迹数据
//    private static ArrayListMultimap<Integer, Dots> dot_number2 = ArrayListMultimap.create(); //Book=1笔迹数据
//    private static ArrayListMultimap<Integer, Dots> dot_number4 = ArrayListMultimap.create(); //笔迹回放数据

    private ArrayListMultimap<Integer, Dot> dot_number = ArrayListMultimap.create();    //每页笔迹数据
    private HashMap<Integer, ArrayListMultimap> map = new HashMap<>();                  //每本笔记数据

    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm：");
    private String tmpLog;
    private MsgReceiver msgReceiver;
    private boolean isRequesting;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //启动Service
        Intent intentOne = new Intent(this, BeibiService.class);
        startService(intentOne);
        Log.i("Beibi", "after StartService");

        //动态注册广播接收器
        msgReceiver = new MsgReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(BeibiService.ACTION_GATT_CONNECTED);
        intentFilter.addAction(BeibiService.RECEVICE_DOT);
        intentFilter.addAction(BeibiService.ACTION_GATT_DISCONNECTED);
        intentFilter.addAction(Api.BG_DOWNLOAD_SUCCESS);
        intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        registerReceiver(msgReceiver, intentFilter);
    }

    private Handler mHandle = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REPLAY:
                    if (popup != null && popup instanceof PopupReplay) {
                        ((PopupReplay) popup).setTotalNumber(gReplayTotalNumber);
                        ((PopupReplay) popup).setCurrentNumber(gReplayCurrentNumber);
                    }
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void initView() {
        tv_pen_name = findViewById(R.id.tv_app_name);
        tv_pen_status = findViewById(R.id.tv_pen_status);

        mylayout = findViewById(R.id.mylayout);
        mPenView = findViewById(R.id.penview);
        mPenView.getViewTreeObserver().addOnGlobalLayoutListener(viewLayoutListener);

        ll_bottom = findViewById(R.id.ll_bottom);

        itv_width = findViewById(R.id.itv_width);
        itv_color = findViewById(R.id.itv_color);
        itv_clear = findViewById(R.id.itv_clear);
        itv_replay = findViewById(R.id.itv_replay);
        itv_more = findViewById(R.id.itv_more);


        tv_pen_status.setOnClickListener(this);
        itv_width.setOnClickListener(this);
        itv_color.setOnClickListener(this);
        itv_clear.setOnClickListener(this);
        itv_replay.setOnClickListener(this);
        itv_more.setOnClickListener(this);
    }

    @Override
    protected void initData() {
        LogUtils.i(TAG, "initData: ");
        calculateBookSize(R.drawable.pager_positive, 300);
        requestPermission1();
    }

    @SuppressLint("SourceLockedOrientationActivity")
    @Override
    protected void onResume() {
        super.onResume();
        LogUtils.i(TAG, "onResume: ");
        //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        if (App.getInstance().isDeviceConnected()) {
            tv_pen_status.setText(getString(R.string.connected, App.getInstance().getDeviceName()));
        } else {
            tv_pen_status.setText(getString(R.string.not_connect_pen));
        }

        if (App.isDrawStoke) {
            //笔锋绘制
            mPenView.setPenMode(DrawView.TYPE_STROKE_PEN);
        } else {
            //普通绘制
            mPenView.setPenMode(DrawView.TYPE_NORMAL_PEN);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        LogUtils.i(TAG, "onPause: ");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LogUtils.i(TAG, "onDestroy: ");
    }

    @Override
    public void onClick(View view) {
        if (!App.getInstance().isDeviceConnected()) {
            showGoConnectDialog();
            return;
        }
        switch (view.getId()) {
            case R.id.tv_pen_status:
                showPenStatusDialog();
                break;
            case R.id.itv_width:
                //showWidthPopup();
                break;
            case R.id.itv_color:
                showColorPopup();
                break;
            case R.id.itv_clear:
                showClearDialog();
                break;
            case R.id.itv_replay:
                showReplayPopup();
                break;
            case R.id.itv_more:
                showMorePopup();
                break;

            default:
                break;
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.KITKAT)
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case FileUtils.GET_FILEPATH_SUCCESS_CODE:
                if (resultCode == Activity.RESULT_OK) {
                    Uri uri = data.getData();
                    LogUtils.i(TAG, "onActivityResult: path=" + uri + ",path2=" + uri.getPath().toString());
                    if (uri != null) {
                        final String path = FileUtils.getRealPathFromURI(mContext, uri);
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                //penCommAgent.readTestData(path);
                            }
                        }).start();
                    }
                }
                break;
            default:
                break;
        }
    }

    /**
     * 背景图位置监听
     */
    private ViewTreeObserver.OnGlobalLayoutListener viewLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            measurePenView();
            mPenView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    };


    /**
     * 测量背景图
     */
    private void measurePenView() {
        if (!hasMeasured) {
            hasMeasured = true;

            BG_WIDTH = mPenView.getMeasuredWidth();
            BG_HEIGHT = mPenView.getMeasuredHeight();
            LogUtils.i(TAG, "measureImgView: BG_WIDTH=" + BG_WIDTH + ",BG_HEIGHT=" + BG_HEIGHT);
        }
    }

    /**
     * 计算本子
     */
    private void calculateBookSize(int resId, int dpi) {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);
        LogUtils.i(TAG, "calculateBookSize: width=" + bitmap.getWidth() + ",height=" + bitmap.getHeight());
        int bmpWidth = bitmap.getWidth();
        int bmpHeight = bitmap.getHeight();
        double bookWidth = ((double) bmpWidth / dpi) * Constants.IN_SIZE;
        double bookHeight = ((double) bmpHeight / dpi) * Constants.IN_SIZE;
        A5_WIDTH = bookWidth;
        A5_HEIGHT = bookHeight;
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveOfflineNumber(Events.ReceiveOffline events) {
        LogUtils.i(TAG, "receiveOfflineNumber : " + events.offlineNum);
        showOfflineNumberDialog(events.offlineNum);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveOfflineProgress(Events.ReceiveOfflineProgress events) {
        LogUtils.i(TAG, "receiveOfflineProgress : " + events.progress + "," + events.finished);
        gProgress = events.progress;
        showOfflineProgressPopup(events.progress);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receiveOfflineDeleteStatus(Events.ReceiveOfflineDeleteStatus events) {
        LogUtils.i(TAG, "receiveOfflineDeleteStatus : " + events.isSucceed);
        if (events.isSucceed) {
            showToast(getString(R.string.offline_delete_success));
        } else {
            showToast(getString(R.string.offline_delete_failed));
        }
    }

    @SuppressLint("SourceLockedOrientationActivity")
    @Subscribe(threadMode = ThreadMode.MAIN, priority = 1)
    public void receiveDot(Events.ReceiveDot receiveDot) {
        Log.i(TAG, "receiveDot: " + receiveDot);
        Dot dot = receiveDot.dot;
        if (dot.OwnerID == 201 && dot.BookID == 63) {
            if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            }
        } else {
            if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            }
        }
        processDots(dot);
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void receivePenStatus(Events.DeviceDisconnected events) {
        LogUtils.i(TAG, "receivePenStatus Disconnected: " + events);
        if (!App.getInstance().isDeviceConnected()) {
            tv_pen_status.setText(getString(R.string.not_connect_pen));
        }
    }

    /**
     * 处理数据（笔记回放时，接收数据不处理）
     *
     * @param dot
     */
    private void processDots(Dot dot) {
        // 回放模式，不接受点
        if (bIsReplay) {
            return;
        }

        processEachDot(dot);
    }

    /**
     * 处理绘制数据
     *
     * @param dot
     */
    private void processEachDot(Dot dot) {
        //Log.i(TAG, "processEachDot: " + dot.toString());
        if (dot.force < 0) {
            return;
        }

        int BookID = dot.BookID;
        int PageID = dot.PageID;
        if (PageID < 0 || BookID < 0) {
            // 谨防笔连接不切页的情况
            return;
        }
        //LogUtils.i(TAG, "processEachDot 1: " + dot);
        if (dot.SectionID == 2 && dot.OwnerID == 200) {
            if (dot.x > 405 && dot.y > 20 && dot.x < 615 && dot.y < 175) {
                LogUtils.i(TAG, "processEachDot: 小尺寸板");
                dot.x = dot.x - 405;
                dot.y = dot.y - 20;
            } else if (dot.x > 0 && dot.y > 200 && dot.x < 260 && dot.y < 390) {
                LogUtils.i(TAG, "processEachDot: 大尺寸板");
                dot.x = dot.x - 0;
                dot.y = dot.y - 200;
            } else {
                return;
            }
        }
        //LogUtils.i(TAG, "processEachDot 2: " + dot);

        if (PageID != gCurPageID || BookID != gCurBookID && dot.type == Dot.DotType.PEN_DOWN) {
            setBackgroundImage(dot.SectionID, dot.OwnerID, BookID, PageID);
            mPenView.setNoteParameter(BookID, PageID);
            drawExistingStroke(BookID, PageID);

            gCurPageID = PageID;
            gCurBookID = BookID;
        }

        //拼接dot点
        float x = DotUtils.joiningTogether(dot.x, dot.fx);
        float y = DotUtils.joiningTogether(dot.y, dot.fy);


        float pointX = DotUtils.getPoint(x, mPenView.getBG_WIDTH(), mPenView.getPAPER_WIDTH(), DotUtils.DIST_PERUNIT);
        float pointY = DotUtils.getPoint(y, mPenView.getBG_HEIGHT(), mPenView.getPAPER_HEIGHT(), DotUtils.DIST_PERUNIT);
        int pointZ = dot.force;

        if (pointZ > 0) {
            if (dot.type == Dot.DotType.PEN_DOWN) {
                //LogUtils.i(TAG, "PEN_DOWN");
                if (PageID < 0 || BookID < 0) {
                    // 谨防笔连接不切页的情况
                    return;
                }

                mPenView.processDot(pointX, pointY, pointZ, 0);
            }

            if (dot.type == Dot.DotType.PEN_MOVE) {
                //LogUtils.i(TAG, "PEN_MOVE");

                mPenView.processDot(pointX, pointY, pointZ, 1);
            }
        } else if (dot.type == Dot.DotType.PEN_UP) {
            //LogUtils.i(TAG, "PEN_UP");

            mPenView.processDot(pointX, pointY, pointZ, 2);
        }

        saveData(dot, gColor, gWidth);
    }

    /**
     * 设置背景图
     *
     * @param sectionID
     * @param ownerID
     * @param bookID
     * @param pageID
     */
    @SuppressLint("SourceLockedOrientationActivity")
    private void setBackgroundImage(int sectionID, int ownerID, int bookID, int pageID) {
        mPenView.reset();
        String filePath = Api.BG_PATH + bookID+"_"+pageID+".png";
        File bgFile = new File(filePath);
        if(bgFile.exists()) {
            setBgImage(filePath);
        } else {
            Api.downloadBg(bookID, pageID ,mContext);
        }

    }

    private void setBgImage(String filePath) {
        File bgFile = new File(filePath);
        if(bgFile.exists()) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            mPenView.replaceBackgroundImage(filePath, 300);
        }
    }

    /**
     * 绘制当前页历史数据
     *
     * @param bookID
     * @param pageID
     */
    private void drawExistingStroke(int bookID, int pageID) {
        ArrayListMultimap<Integer, Dot> dot_number4 = map.get(bookID);
        /*if (bookID == 100) {
            dot_number4 = dot_number;
        } else if (bookID == 0) {
            dot_number4 = dot_number1;
        } else if (bookID == 1) {
            dot_number4 = dot_number2;
        }*/

        if (dot_number4 == null || dot_number4.isEmpty()) {
            return;
        }

        Set<Integer> keys = dot_number4.keySet();
        for (int key : keys) {
            if (key == pageID) {
                List<Dot> dots = dot_number4.get(key);
                LogUtils.i(TAG, "DrawExistingStroke: " + dots.size());
                for (int i = 0; i < dots.size(); i++) {
                    Dot dot = dots.get(i);

                    setPenColor(dot.color);
                    mPenView.setNoteParameter(dot.BookID, dot.PageID);
                    mPenView.processDot(dot);
                }
            }
        }
    }

    /**
     * 回放数据处理
     *
     * @param BookID
     * @param PageID
     * @param SpeedID
     */
    private void ReplayCurrentPage(int BookID, int PageID, int SpeedID) {
        ArrayListMultimap<Integer, Dot> dot_number4 = map.get(BookID);
        /*if (BookID == 100) {
            dot_number4 = dot_number;
        } else if (BookID == 0) {
            dot_number4 = dot_number1;
        } else if (BookID == 1) {
            dot_number4 = dot_number2;
        }*/

        if (dot_number4 == null || dot_number4.isEmpty()) {
            bIsReplay = false;
            return;
        }


        Set<Integer> keys = dot_number4.keySet();
        for (int key : keys) {
            bIsReplay = true;
            if (key == PageID) {
                List<Dot> dots = dot_number4.get(key);
                gReplayTotalNumber = dots.size();
                gReplayCurrentNumber = 0;
                for (final Dot dot : dots) {
                    //笔锋绘制方法
                    if (bIsReplay) {
                        SetPenColor(dot.color);
                        mPenView.processDot(dot);
                        gReplayCurrentNumber++;
                        if (popup instanceof PopupReplay && popup.isShowing()) {
                            gSpeed = ((PopupReplay) popup).getSpeed();
                        }
                        SystemClock.sleep(gSpeed * 10);
                        mHandle.sendEmptyMessage(MSG_REPLAY);
                    }
                }
            }
        }

        bIsReplay = false;
        if (popup instanceof PopupReplay) {
            ((PopupReplay) popup).setStart(false);
        }
    }

    /**
     * 回放
     */
    public void RunReplay() {
        if (gCurPageID < 0) {
            bIsReplay = false;
            return;
        }
        mPenView.reset();
        new Thread(new Runnable() {
            @Override
            public void run() {
                ReplayCurrentPage(gCurBookID, gCurPageID, gSpeed);
            }
        }).start();
    }

    /**
     * 内存存储数据
     *
     * @param dot
     * @param color
     * @param width
     */
    private void saveData(Dot dot, int color, int width) {
        dot_number.put(dot.PageID, dot);
        if (dot.BookID != gCurBookID) {
            map.put(dot.BookID, dot_number);
            dot_number.clear();
        } else {
            map.put(dot.BookID, dot_number);
        }
        //LogUtils.i(TAG, "saveData: " + map.size());
        /*Dots dots = new Dots(dot, color, width);
        if (dot.BookID == 100) {
            dot_number.put(dot.PageID, dots);
        } else if (dot.BookID == 0) {
            dot_number1.put(dot.PageID, dots);
        } else if (dot.BookID == 1) {
            dot_number2.put(dot.PageID, dots);
        }*/

        saveOutDotLog(dot);
    }



    /**
     * 储存日志
     *
     * @param dot
     */
    private void saveOutDotLog(Dot dot) {
        Date curDate = new Date(System.currentTimeMillis());
        String str = formatter.format(curDate);
        String logName = str.substring(0, 13);
        boolean bLogStart = false;
        //LogUtils.i(TAG, "saveOutDotLog: " + logName);

        if (logName.equals(tmpLog)) {
            bLogStart = false;
        } else {
            bLogStart = true;
            tmpLog = logName;
        }
        if (isSaveLog) {
            String fileName = str.substring(0, 10) + ".log";
            if (bLogStart) {
                BLEFileUtil.writeTxtToFile("-------------------------TQL SmartPen LOG--------------------------", LOG_PATH, fileName);
            }
            BLEFileUtil.writeTxtToFile(dot.toString(), LOG_PATH, fileName);
        }

    }

    /**
     * 设置笔记颜色
     *
     * @param ColorIndex
     */
    private void setPenColor(int ColorIndex) {
        switch (ColorIndex) {
            case 0:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.GRAY));
                break;
            case 1:
                mPenView.setPenColor(Color.RED);
                break;
            case 2:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.rgb(192, 192, 0)));
                break;
            case 3:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.rgb(0, 128, 0)));
                break;
            case 4:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.rgb(0, 0, 192)));
                break;
            case 5:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.BLUE));
                break;
            case 6:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.BLACK));
                break;
            case 7:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.MAGENTA));
                break;
            case 8:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.CYAN));
                break;
        }
    }

    /**
     * 获取本页手写识别数据
     *
     * @param BookID
     * @param PageID
     * @return
     */
    public List<Dot> getRecognitionData(int BookID, int PageID) {
        List<Dot> dotsList = new ArrayList<>();
        /*if (BookID == 100) {
            dot_number4 = dot_number;
        } else if (BookID == 0) {
            dot_number4 = dot_number1;
        } else if (BookID == 1) {
            dot_number4 = dot_number2;
        }*/
        ArrayListMultimap<Integer, Dot> dot_number = map.get(BookID);

        Set<Integer> keys = dot_number.keySet();
        for (int key : keys) {
            if (key == PageID) {
                List<Dot> list = dot_number.get(key);

                for (Dot dot : list) {
                    dotsList.add(dot);
                }
            }
        }

        return dotsList;
    }

    /**
     * 颜色
     */
    private void showColorPopup() {
        popup = new PopupColor(mContext);
        ((PopupColor) popup).setListener(popupListener);
        ((PopupColor) popup).setSelectIndex(gColor);

        int popupWidth = ((PopupColor) popup).getPopupWidth();    //获取测量后的宽度
        int popupHeight = ((PopupColor) popup).getPopupHeight();  //获取测量后的高度

        int[] location = new int[2];
        ll_bottom.getLocationOnScreen(location);

        LogUtils.i(TAG, "showPopup:location=" + location[0] + "," + location[1] + ",popupWidth=" + popupWidth + ",popupHeight=" + popupHeight);

        popup.showAtLocation(ll_bottom, Gravity.TOP, (location[0]),
                location[1] - popupHeight);
    }

    /**
     * 清除
     */
    private void showClearDialog() {
        Dialog dialog = new Dialog(this, R.style.customDialog);
        View view = LayoutInflater.from(this).inflate(R.layout.dialog_clear, null);

        TextView cancel = view.findViewById(R.id.tv_cancel);
        TextView delete = view.findViewById(R.id.tv_ok);

        cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
            }
        });
        delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
                mPenView.reset();
                if (!bIsReplay) {
                    dot_number.clear();
                    /*dot_number1.clear();
                    dot_number2.clear();
                    dot_number4.clear();*/
                }
            }
        });

        dialog.setContentView(view);
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);

        dialog.show();
    }

    /**
     * 回放
     */
    private void showReplayPopup() {
        if (popup == null || !(popup instanceof PopupReplay)) {
            popup = new PopupReplay(mContext);
        }
        ((PopupReplay) popup).setListener(popupListener);

        ((PopupReplay) popup).setTotalNumber(gReplayTotalNumber);
        ((PopupReplay) popup).setCurrentNumber(gReplayCurrentNumber);
        ((PopupReplay) popup).setSpeed(gSpeed);
        ((PopupReplay) popup).setStart(bIsReplay);

        int popupWidth = ((PopupReplay) popup).getPopupWidth();    //获取测量后的宽度
        int popupHeight = ((PopupReplay) popup).getPopupHeight();  //获取测量后的高度

        int[] location = new int[2];
        ll_bottom.getLocationOnScreen(location);

        LogUtils.i(TAG, "showPopup:location=" + location[0] + "," + location[1] + ",popupWidth=" + popupWidth + ",popupHeight=" + popupHeight);

        popup.showAtLocation(ll_bottom, Gravity.TOP, location[0], location[1] - popupHeight);
    }

    /**
     * 更多
     */
    private void showMorePopup() {
        if (popup == null || !(popup instanceof PopupMore)) {
            popup = new PopupMore(mContext);
        }
        ((PopupMore) popup).setListener(popupListener);

        int popupWidth = ((PopupMore) popup).getPopupWidth();    //获取测量后的宽度
        int popupHeight = ((PopupMore) popup).getPopupHeight();  //获取测量后的高度

        int[] location = new int[2];
        ll_bottom.getLocationOnScreen(location);

        LogUtils.i(TAG, "showPopup:location=" + location[0] + "," + location[1] + ",popupWidth=" + popupWidth + ",popupHeight=" + popupHeight);

        popup.showAtLocation(ll_bottom, Gravity.TOP | Gravity.RIGHT, location[0], location[1] - popupHeight);
    }

    /**
     * 离线
     */
    private void showOfflinePopup() {
        if (popup == null || !(popup instanceof PopupOffline)) {
            popup = new PopupOffline(mContext);
        }
        ((PopupOffline) popup).setListener(popupListener);

        int popupWidth = ((PopupOffline) popup).getPopupWidth();    //获取测量后的宽度
        int popupHeight = ((PopupOffline) popup).getPopupHeight();  //获取测量后的高度

        int[] location = new int[2];
        ll_bottom.getLocationOnScreen(location);

        LogUtils.i(TAG, "showPopup:location=" + location[0] + "," + location[1] + ",popupWidth=" + popupWidth + ",popupHeight=" + popupHeight);

        popup.showAtLocation(ll_bottom, Gravity.TOP | Gravity.RIGHT, (location[0]), location[1] - popupHeight);
    }


    /**
     * 离线数据下载进度
     */
    private void showOfflineProgressPopup(int progress) {
        if (popup == null || !(popup instanceof PopupOfflineProgress)) {
            popup = new PopupOfflineProgress(mContext);
        }
        ((PopupOfflineProgress) popup).setListener(popupListener);
        popup.showAtLocation(mPenView, Gravity.CENTER, 0, 0);

        ((PopupOfflineProgress) popup).setProgress(progress);
        if (progress == 100) {
            mHandle.postDelayed(new Runnable() {
                @Override
                public void run() {
                    popup.dismiss();
                }
            }, 1000);
        }
    }

    /**
     * 笔状态dialog
     */
    private void showPenStatusDialog() {
        Dialog dialog = new Dialog(this, R.style.customDialog);
        View view = LayoutInflater.from(this).inflate(R.layout.dialog_pen_status, null);
        RelativeLayout rl_close = view.findViewById(R.id.rl_close);
        tv_pen_name = view.findViewById(R.id.tv_pen_name);
        TextView tv_pen_mac = view.findViewById(R.id.tv_pen_mac);
        TextView tv_pen_battery = view.findViewById(R.id.tv_pen_battery);
        TextView tv_change_pen = view.findViewById(R.id.tv_change_pen);

        tv_pen_name.setText(getString(R.string.pen_name, App.getInstance().getDeviceName()));
        tv_pen_mac.setText(getString(R.string.pen_address, App.getInstance().getDeviceAddress()));
        tv_pen_battery.setText(getString(R.string.pen_battery, App.getInstance().getDeviceBattery()));

        rl_close.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
            }
        });
        tv_change_pen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
                Intent intent = new Intent(mContext, SearchActivity.class);
                startActivity(intent);
            }
        });

        dialog.setContentView(view);
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);

        dialog.show();
    }

    /**
     * 去连接笔dialog
     */
    private void showGoConnectDialog() {
        Dialog dialog = new Dialog(this, R.style.customDialog);
        View view = LayoutInflater.from(this).inflate(R.layout.dialog_go_connect, null);
        TextView cancel = view.findViewById(R.id.cancel);
        TextView connect = view.findViewById(R.id.connect);
        cancel.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
            }
        });
        connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
                Intent intent = new Intent(mContext, SearchActivity.class);
                startActivity(intent);
            }
        });

        dialog.setContentView(view);
        dialog.setCancelable(false);
        dialog.setCanceledOnTouchOutside(false);

        dialog.show();
    }

    /**
     * 离线数据数量dialog
     *
     * @return
     */
    private void showOfflineNumberDialog(int number) {
        Dialog dialog = new Dialog(mContext, R.style.customDialog);
        //alertDialog是否可以点击外围消失
        dialog.setCanceledOnTouchOutside(false);
        dialog.setCancelable(false);

        View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_offline_number, null);
        TextView offNumTextView = view.findViewById(R.id.textView2);
        TextView confirmBtn = view.findViewById(R.id.button);

        offNumTextView.setText(number + "bytes");

        confirmBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });

        dialog.setContentView(view);

        dialog.show();
    }

    /**
     * 弹出层事件
     */
    PopupListener popupListener = new PopupListener() {
        @Override
        public void click(int id) {
            switch (id) {
                case R.id.ll_recognition:
                    Intent intentRecon = new Intent(mContext, RecognitionActivity.class);
                    List<Dot> list = getRecognitionData(gCurBookID, gCurPageID);
                    DataHolder.getInstance().setData("value", list);
                    startActivity(intentRecon);
                    break;
                case R.id.ll_offline:
                    showOfflinePopup();
                    break;
                case R.id.ll_setting:
                    Intent paramIntent = new Intent(mContext, ParameterActivity.class);
                    startActivity(paramIntent);
                    break;
                case R.id.ll_ota:
                    Intent intent = new Intent(mContext, OTAActivity.class);
                    intent.putExtra("addr", App.getInstance().getDeviceAddress());
                    intent.putExtra("type", App.getInstance().getDeviceType());
                    startActivity(intent);
                    break;
                case R.id.ll_txt:
                    FileUtils.openFilePath(MainActivity.this);
                    break;
                case R.id.ll_about:
                    Intent aboutIntent = new Intent(mContext, AboutActivity.class);
                    startActivity(aboutIntent);
                    break;
                case R.id.ll_offline_back:
                    popup.dismiss();
                    showMorePopup();
                    break;
                case R.id.ll_start_offline:
                    startOffline = true;
                    showProgress = true;
                    //penCommAgent.ReqOfflineDataTransfer(true);
                    break;
                case R.id.ll_stop_offline:
                    //penCommAgent.ReqOfflineDataTransfer(false);
                    startOffline = false;
                    break;
                case R.id.tv_pause_continue:
                    //pauseOrContinue();
                    break;
                case R.id.ll_delete_offline:
                    //penCommAgent.RemoveOfflineData();
                    break;
                case R.id.ll_offline_number:
                    //penCommAgent.getPenOfflineDataList();
                    break;

                case R.id.iv_width_1:
                    gWidth = 1;
                    mPenView.setPenWidth(gWidth);
                    break;
                case R.id.iv_width_2:
                    gWidth = 2;
                    mPenView.setPenWidth(gWidth);
                    break;
                case R.id.iv_width_3:
                    gWidth = 3;
                    mPenView.setPenWidth(gWidth);
                    break;
                case R.id.iv_width_4:
                    gWidth = 4;
                    mPenView.setPenWidth(gWidth);
                    break;
                case R.id.iv_width_5:
                    gWidth = 5;
                    mPenView.setPenWidth(gWidth);
                    break;

                case R.id.iv_color_black:
                    gColor = 1;
                    SetPenColor(gColor);
                    break;
                case R.id.iv_color_red:
                    gColor = 2;
                    SetPenColor(gColor);
                    break;
                case R.id.iv_color_blue:
                    gColor = 3;
                    SetPenColor(gColor);
                    break;
                case R.id.iv_color_green:
                    gColor = 4;
                    SetPenColor(gColor);
                    break;
                case R.id.iv_color_yellow:
                    gColor = 5;
                    SetPenColor(gColor);
                    break;
                case R.id.iv_color_orange:
                    gColor = 6;
                    SetPenColor(gColor);
                    break;
                case R.id.iv_replay_start:
                    if (((PopupReplay) popup).isStart()) {
                        ((PopupReplay) popup).setStart(false);
                        bIsReplay = false;
                    } else {
                        ((PopupReplay) popup).setStart(true);
                        bIsReplay = true;
                        RunReplay();
                    }
                    break;
                case R.id.tv_replay_speed:
                    gSpeed = ((PopupReplay) popup).getSpeed();
                    break;
            }
        }
    };

    /**
     * 设置笔记颜色
     *
     * @param ColorIndex
     */
    public void SetPenColor(int ColorIndex) {
        switch (ColorIndex) {
            case 1:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.BLACK));
                break;
            case 2:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.RED));
                break;
            case 3:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.BLUE));
                break;
            case 4:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.GREEN));
                break;
            case 5:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.YELLOW));
                break;
            case 6:
                mPenView.setPenColor(ColorUtil.int2Hex(Color.rgb(255, 143, 33)));
                break;
        }
    }

    /**
     * 读取保存的Dot点数据
     */
    public void testReadLogData() {
        mHandle.postDelayed(new Runnable() {
            @Override
            public void run() {
                try {
                    String data = BLEFileUtil.readFile("/mnt/sdcard/tql/test.txt");
                    Gson gson = new Gson();
                    List<Dot> dotList = gson.fromJson(data, new TypeToken<List<Dot>>() {
                    }.getType());
                    int size = dotList.size();
                    for (int i = 0; i < size; i++) {
                        final Dot dot = dotList.get(i);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                processDots(dot);
                            }
                        });
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }, 5000);
    }

    /**
     * 广播接收器
     * @author moyc
     *
     */
    public class MsgReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action  = intent.getAction();
            if (BeibiService.ACTION_GATT_CONNECTED.equals(action)) {
                tv_pen_status.setText(getString(R.string.connected, App.getInstance().getDeviceName()));
                tv_pen_name.setText(getString(R.string.pen_name, App.getInstance().getDeviceName()));
            } else if(BeibiService.RECEVICE_DOT.equals(action)) {
                Dot dot = (Dot)intent.getExtras().get("dot");
                processDots(dot);
            } else if(BeibiService.ACTION_GATT_DISCONNECTED.equals(action)) {
                tv_pen_status.setText(getString(R.string.not_connect_pen));
                tv_pen_name.setText("");
            } else if(Api.BG_DOWNLOAD_SUCCESS.equals(action)) {
                String filePath = intent.getStringExtra("pnfFile");
                setBgImage(filePath);
            } else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
                switch (state) {
                    case BluetoothAdapter.STATE_ON:
                        requestPermission1();
                        break;
                }
            }
        }
    }

    /**
     * 请求写文件权限
     */
    private void requestPermission1() {
        if (PackageManager.PERMISSION_GRANTED != ActivityCompat
                .checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            if (isRequesting)
                return;
            isRequesting = true;
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST1);
            return;
        }
        requestPermission2();
    }

    /**
     * 请求位置权限
     */
    private void requestPermission2() {
        if (PackageManager.PERMISSION_GRANTED != ActivityCompat
                .checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)) {
            if (isRequesting)
                return;
            isRequesting = true;
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST2);
            return;
        }
        requestPermission3();
    }

    /**
     * 请求精确位置权限
     */
    private void requestPermission3() {
        if (PackageManager.PERMISSION_GRANTED != ActivityCompat
                .checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
            if (isRequesting)
                return;
            isRequesting = true;
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST3);
            return;
        }
    }

    private static final int PERMISSION_REQUEST1 = 100;
    private static final int PERMISSION_REQUEST2 = 200;
    private static final int PERMISSION_REQUEST3 = 400;
    private static final int REQUEST_BLUETOOTH_ENABLE = 300;


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST1:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    isRequesting = false;
                    requestPermission2();
                } else {
                    AlertDialog dialog = new AlertDialog.Builder(
                            this, R.style.Theme_AppCompat_Light_Dialog)
                            .setTitle(R.string.permission_title).setMessage(R.string.permission_sdcard_message)
                            .setPositiveButton(R.string.permission_button, (dialog1, which) -> {
                                isRequesting = false;
                                dialogCancel(dialog1);
                            }).setCancelable(false).create();
                    dialogShow(dialog);
                }
                break;
            case PERMISSION_REQUEST2:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    isRequesting = false;
                    //requestBluetooth();
                    requestPermission3();
                } else {
                    AlertDialog dialog = new AlertDialog.Builder(
                            this, R.style.Theme_AppCompat_Light_Dialog)
                            .setTitle(R.string.permission_title).setMessage(R.string.permission_location_message)
                            .setPositiveButton(R.string.permission_button, (dialog1, which) -> {
                                isRequesting = false;
                                dialogCancel(dialog1);
                            }).setCancelable(false).create();
                    dialogShow(dialog);
                }
                break;
            case PERMISSION_REQUEST3:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    isRequesting = false;
                } else {
                    AlertDialog dialog = new AlertDialog.Builder(
                            this, R.style.Theme_AppCompat_Light_Dialog)
                            .setTitle(R.string.permission_title).setMessage(R.string.permission_fine_location_message)
                            .setPositiveButton(R.string.permission_button, (dialog1, which) -> {
                                isRequesting = false;
                                dialogCancel(dialog1);
                            }).setCancelable(false).create();
                    dialogShow(dialog);
                }
                break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
                break;
        }
    }

}
